/*
 * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA
 * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @defgroup bt_mesh_dfd_srv Firmware Distribution Server model
 * @ingroup bt_mesh_dfd
 * @{
 * @brief API for the Firmware Distribution Server model
 */

#ifndef _BLE_MESH_v11_DFD_SRV_H__
#define _BLE_MESH_v11_DFD_SRV_H__

#include "mesh/access.h"
#include "mesh_v1.1/dfu/dfd.h"
#include "mesh_v1.1/dfu/dfu_cli.h"
#include "mesh_v1.1/mbt/blob_cli.h"
#include "mesh_v1.1/mbt/blob_srv.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifndef CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX
#define CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX 0
#endif

#ifndef CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE
#define CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE 0
#endif

#ifndef CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE
#define CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE 0
#endif

struct bt_mesh_dfd_srv;

#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD
/**
 *
 *  @brief Initialization parameters for the @ref bt_mesh_dfd_srv with OOB
 *         upload support.
 *
 *  @param[in] _cb                Pointer to a @ref bt_mesh_dfd_srv_cb instance.
 *  @param[in] _oob_schemes       Array of OOB schemes supported by the server,
 *                                each scheme being a code point from the
 *                                Bluetooth SIG Assigned Numbers document.
 *  @param[in] _oob_schemes_count Number of schemes in @c _oob_schemes.
 */
#define BT_MESH_DFD_SRV_OOB_INIT(_cb, _oob_schemes, _oob_schemes_count) \
    {                                                                   \
        .cb = _cb,                                                      \
        .dfu = BLE_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb),         \
        .upload = {                                                     \
            .blob = { .cb = &_bt_mesh_dfd_srv_blob_cb },                \
        },                                                              \
        .oob_schemes = {                                                \
            .schemes = _oob_schemes,                                    \
            .count = _oob_schemes_count,                                \
        },                                                              \
    }
#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */

/**
 *
 *  @brief Initialization parameters for the @ref bt_mesh_dfd_srv.
 *
 *  @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance.
 */
#define BT_MESH_DFD_SRV_INIT(_cb)                                \
    {                                                            \
        .cb = _cb,                                               \
        .dfu = BLE_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb),  \
        .upload = {                                              \
            .blob = { .cb = &_bt_mesh_dfd_srv_blob_cb },         \
        },                                                       \
    }

/**
 *
 *  @brief Firmware Distribution Server model Composition Data entry.
 *
 *  @param _srv Pointer to a @ref bt_mesh_dfd_srv instance.
 */
#define BT_MESH_MODEL_DFD_SRV(_srv)                                         \
    BT_MESH_MODEL_DFU_CLI(&(_srv)->dfu),                                    \
    BT_MESH_MODEL_BLOB_SRV(&(_srv)->upload.blob),                           \
    BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_DFD_SRV, _bt_mesh_dfd_srv_op, NULL, \
             _srv, &_bt_mesh_dfd_srv_cb)

/** Firmware Distribution Server callbacks: */
struct bt_mesh_dfd_srv_cb {

    /** @brief Slot receive callback.
     *
     *  Called at the start of an upload procedure. The callback must fill
     *  @c io with a pointer to a writable BLOB stream for the Firmware Distribution
     *  Server to write the firmware image to.
     *
     *  @param srv  Firmware Distribution Server model instance.
     *  @param slot DFU image slot being received.
     *  @param io   BLOB stream response pointer.
     *
     *  @return 0 on success, or (negative) error code otherwise.
     */
    int (*recv)(struct bt_mesh_dfd_srv *srv,
                const struct bt_mesh_dfu_slot *slot,
                const struct bt_mesh_blob_io **io);

#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD
    /** @brief Firmware upload OOB start callback.
     *
     *  Called at the start of an OOB firmware upload. The application must
     *  start a firmware check using an OOB mechanism, and then call
     *  @ref bt_mesh_dfd_srv_oob_check_complete. Depending on the return
     *  value of this function, the application must then start storing the
     *  firmware image using an OOB mechanism, and call
     *  @ref bt_mesh_dfd_srv_oob_store_complete. This callback is mandatory
     *  to support OOB uploads.
     *
     *  @param srv          Firmware Distribution Server model instance.
     *  @param slot         Slot to be used for the upload.
     *  @param uri          Pointer to buffer containing the URI used to
     *                      check for new firmware.
     *  @param uri_len      Length of the URI buffer.
     *  @param fwid         Pointer to buffer containing the current
     *                      firmware ID to be used when checking for
     *                      availability of new firmware.
     *  @param fwid_len     Length of the current firmware ID. Must be set
     *                      to the length of the new firmware ID if it is
     *                      available, or to 0 if new firmware is not
     *                      available.
     *
     *  @return BT_MESH_DFD_SUCCESS on success, or error code otherwise.
     */
    int (*start_oob_upload)(struct bt_mesh_dfd_srv *srv,
                            const struct bt_mesh_dfu_slot *slot,
                            const char *uri, uint8_t uri_len,
                            const uint8_t *fwid, uint16_t fwid_len);

    /** @brief Cancel store OOB callback
     *
     *  Called when an OOB store is cancelled. The application must stop
     *  any ongoing OOB image transfer. This callback is mandatory to
     *  support OOB uploads.
     *
     *  @param srv  Firmware Distribution Server model instance.
     *  @param slot DFU image slot to cancel
     */
    void (*cancel_oob_upload)(struct bt_mesh_dfd_srv *srv,
                              const struct bt_mesh_dfu_slot *slot);

    /** @brief Get the progress of an ongoing OOB store
     *
     *  Called by the Firmware Distribution Server model when it needs to
     *  get the current progress of an ongoing OOB store from the
     *  application. This callback is mandatory to support OOB uploads.
     *
     *  @param srv  Firmware Distribution Server model instance.
     *  @param slot DFU image slot to get progress for.
     *
     *  @return The current progress of the ongoing OOB store, in percent.
     */
    uint8_t (*oob_progress_get)(struct bt_mesh_dfd_srv *srv,
                                const struct bt_mesh_dfu_slot *slot);
#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */

    /** @brief Slot delete callback.
     *
     *  Called when the Firmware Distribution Server is about to delete a DFU image slot.
     *  All allocated data associated with the firmware slot should be
     *  deleted.
     *
     *  @param srv  Firmware Update Server instance.
     *  @param slot DFU image slot being deleted.
     */
    void (*del)(struct bt_mesh_dfd_srv *srv,
                const struct bt_mesh_dfu_slot *slot);

    /** @brief Slot send callback.
     *
     *  Called at the start of a distribution procedure. The callback must
     *  fill @c io with a pointer to a readable BLOB stream for the Firmware
     *  Distribution Server to read the firmware image from.
     *
     *  @param srv  Firmware Distribution Server model instance.
     *  @param slot DFU image slot being sent.
     *  @param io   BLOB stream response pointer.
     *
     *  @return 0 on success, or (negative) error code otherwise.
     */
    int (*send)(struct bt_mesh_dfd_srv *srv,
                const struct bt_mesh_dfu_slot *slot,
                const struct bt_mesh_blob_io **io);

    /** @brief Phase change callback (Optional).
     *
     *  Called whenever the phase of the Firmware Distribution Server changes.
     *
     *  @param srv  Firmware Distribution Server model instance.
     *  @param phase  New Firmware Distribution phase.
     */
    void (*phase)(struct bt_mesh_dfd_srv *srv, enum bt_mesh_dfd_phase phase);
};

/** Firmware Distribution Server instance. */
struct bt_mesh_dfd_srv {
    const struct bt_mesh_dfd_srv_cb *cb;
    const struct bt_mesh_model *mod;
    struct bt_mesh_dfu_cli dfu;
    struct bt_mesh_dfu_target targets[CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX];
    struct bt_mesh_blob_target_pull pull_ctxs[CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX];
    const struct bt_mesh_blob_io *io;
    uint16_t target_cnt;
    uint16_t slot_idx;
    bool apply;
    enum bt_mesh_dfd_phase phase;
    struct bt_mesh_blob_cli_inputs inputs;

    struct {
        enum bt_mesh_dfd_upload_phase phase;
        struct bt_mesh_dfu_slot *slot;
        const struct flash_area *area;
        struct bt_mesh_blob_srv blob;
#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD
        bool is_oob;
        bool is_pending_oob_check;
        struct {
            uint8_t uri_len;
            char uri[CONFIG_BLE_MESH_DFU_URI_MAXLEN];
            uint16_t current_fwid_len;
            uint8_t current_fwid[CONFIG_BLE_MESH_DFU_FWID_MAXLEN];
            struct bt_mesh_msg_ctx ctx;
        } oob;
#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */
    } upload;

#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD
    struct {
        const uint8_t *schemes;
        const uint8_t count;
    } oob_schemes;
#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */
};

#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD
/** @brief Call when an OOB check has completed or failed
 *
 *  This should be called by the application after an OOB check started by the @c start_oob_upload
 *  callback has completed or failed. The @p status param should be set to one of the following
 *  values:
 *
 *  * @c BT_MESH_DFD_SUCCESS if the check was successful and a new firmware ID was found.
 *  * @c BT_MESH_DFD_ERR_URI_MALFORMED if the URI is not formatted correctly.
 *  * @c BT_MESH_DFD_ERR_URI_NOT_SUPPORTED if the URI scheme is not supported by the node.
 *  * @c BT_MESH_DFD_ERR_URI_UNREACHABLE if the URI can't be reached.
 *  * @c BT_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE if the check completes successfully but no new
 *    firmware is available.
 *
 *  If this function returns 0, the application should then download the firmware to the
 *  slot. If an error code is returned, the application should abort the OOB upload.
 *
 *  @param srv      Firmware Distribution Server model instance.
 *  @param slot     The slot used in the OOB upload.
 *  @param status   The result of the firmware check.
 *  @param fwid     If the check was successful and new firmware found, this should point to a
 *                  buffer containing the new firmware ID to store.
 *  @param fwid_len The length of the firmware ID pointed to by @p fwid.
 *
 *  @return 0 on success, (negative) error code otherwise.
 */
int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv,
                                       const struct bt_mesh_dfu_slot *slot, int status,
                                       uint8_t *fwid, size_t fwid_len);

/** @brief Call when an OOB store has completed or failed
 *
 *  This should be called by the application after an OOB store started after a successful call to
 *  @c bt_mesh_dfd_srv_oob_check_complete has completed successfully or failed.
 *
 *  @param srv          Firmware Distribution Server model instance.
 *  @param slot         The slot used when storing the firmware image.
 *  @param success      @c true if the OOB store completed successfully, @c false otherwise.
 *  @param size         The size of the stored firmware image, in bytes.
 *  @param metadata     Pointer to the metadata received OOB, or @c NULL if no metadata was
 *                      received.
 *  @param metadata_len Size of the metadata pointed to by @p metadata.
 *
 *  @return 0 on success, (negative) error code otherwise.
 */
int bt_mesh_dfd_srv_oob_store_complete(struct bt_mesh_dfd_srv *srv,
                                       const struct bt_mesh_dfu_slot *slot, bool success,
                                       size_t size, const uint8_t *metadata, size_t metadata_len);
#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */

/** @cond INTERNAL_HIDDEN */
extern const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[];
extern const struct bt_mesh_model_cb _bt_mesh_dfd_srv_cb;
extern const struct bt_mesh_dfu_cli_cb _bt_mesh_dfd_srv_dfu_cb;
extern const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb;
/** @endcond */

#ifdef __cplusplus
}
#endif

#endif /* _BLE_MESH_v11_DFD_SRV_H__ */

/** @} */
